package gbase

import (
	"fmt"
	"strconv"

	jsoniter "github.com/json-iterator/go"
)

// Nullable 泛型类型，用于处理 JSON 中的空字符串、数字、字符串数字
// 目前支持 int, int64, float64 数字类型
type JsonNum[T TNum] struct {
	Value T
	Valid bool // 是否有有效值
}

// 类型别名，便于使用
// type JsonInt = JsonNum[int]
// type JsonInt64 = JsonNum[int64]
// type JsonFloat64 = JsonNum[float64]

func (n *JsonNum[T]) UnmarshalJSON(data []byte) error {
	// 尝试直接解析为数字
	var num T
	if err := jsoniter.Unmarshal(data, &num); err == nil {
		n.Value = num
		n.Valid = true
		return nil
	}

	// 尝试解析为字符串
	var str string
	if err := jsoniter.Unmarshal(data, &str); err != nil {
		return err
	}

	// 如果是空字符串，设置为0
	if str == "" {
		n.Value = 0
		n.Valid = false
		return nil
	}

	// 根据类型解析字符串
	var val T
	switch any(val).(type) {
	case int:
		v, err := strconv.Atoi(str)
		if err != nil {
			return err
		}
		n.Value = T(v)
	case int64:
		v, err := strconv.ParseInt(str, 10, 64)
		if err != nil {
			return err
		}
		n.Value = T(v)
	case float64:
		v, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return err
		}
		n.Value = T(v)
	}

	n.Valid = true
	return nil
}

func (n JsonNum[T]) MarshalJSON() ([]byte, error) {
	if !n.Valid {
		return []byte("null"), nil
	}
	return jsoniter.Marshal(n.Value)
}

func (n JsonNum[T]) Get() T {
	return n.Value
}

func (n JsonNum[T]) String() string {
	if !n.Valid {
		return ""
	}
	switch any(n.Value).(type) {
	case int, int64:
		return strconv.FormatInt(int64(n.Value), 10)
	case float64:
		return strconv.FormatFloat(float64(n.Value), 'f', -1, 64)
	default:
		return strconv.FormatFloat(float64(n.Value), 'f', -1, 64)
	}
}

// FromString 从字符串创建 JsonNum（包级函数）
// 如果字符串为空，返回 Valid=false 的 JsonNum
func JsonNumFromString[T TNum](numStr string) (JsonNum[T], error) {
	var result JsonNum[T]

	// 如果是空字符串，设置为无效值
	if numStr == "" {
		result.Value = 0
		result.Valid = false
		return result, nil
	}

	// 根据类型解析字符串
	var val T
	switch any(val).(type) {
	case int:
		v, err := strconv.Atoi(numStr)
		if err != nil {
			return result, err
		}
		result.Value = T(v)
	case int64:
		v, err := strconv.ParseInt(numStr, 10, 64)
		if err != nil {
			return result, err
		}
		result.Value = T(v)
	case float64:
		v, err := strconv.ParseFloat(numStr, 64)
		if err != nil {
			return result, err
		}
		result.Value = T(v)
	default:
		return result, fmt.Errorf("unsupported type for FromString")
	}

	result.Valid = true
	return result, nil
}
